[日本語Alexa] Cognito UserPoolでアカウントを管理して特定のデバイスの情報にアクセスする
1 はじめに
AIソリューション部の平内(SIN)です。
今回は、AWS IoT経由でAWS上にデータを保存(今回は、DynamoDBを想定)するデバイスがあった時、その情報を再生するスキルを作成してみました。
利用者は、ユーザー登録を行うことで、手元のデバイスを識別するID(ここではデバイスIDと表現)を自分のアカウントに紐付けるイメージです。
アカウントリンクを使用すると、強制的にログインが必要になり、今回使用した、Cognito User Poolでは、サインアップ機能も有効にできるので、スキルを有効化するタイミングでユーザー登録(作成)が可能です。
デバイスIDをユーザーの登録の必須項目としておくことで、「ユーザー登録」=「デバイスID紐づけ」という仕組みが作れることになります。
2 構成
構成については、概ね以下のとおりです。
- ① IoT経由でデバイス固有のIDをキーにして、DynamoDBのデータを更新するデバイスがあります。(想定)
- ② スキルは、有効にするためにアカウントリンクが必要です。
- ③ アカウントリンク時にCognito User Poolでユーザーを新規に作成します。
- ④ この時、ユーザーは、デバイスのIDを入力します。
- ⑤ スキルから呼び出さ出されたLambdaでは、アクセストークンでデバイスIDを取得し、DynamoDBにアクセスします。
※ DynamoDBへのパーミッションは、RoleでLambdaへ付与されています。Cognito User Poolは、OAuth2サーバとしてのみ機能しています。
3 Cognito UserPoll
OAuth2サーバとして利用するため、Cognito User Poolを使用します。
参考:[日本語Alexa] Cognito User Pool によるアカウントリンク
必須属性にemai及び、profileの2つを設定しました。このprofile属性にデバイスIDを格納します。
アプリクライアントは、クライアントシークレット生成を有効にして作成します。
ドメインは、利用可能な名前に制限がありますが、ここでは、alexa-user-poolとしました。
アプリクライアントの設定は、以下のとおりです。
- 有効なIDプロパイダ: Cognito User Pool
- コールバックURL: スキルのアカウントリンクの設定画面からコピーします
- 許可まれているOAuthフロー: Authoraization code grant
- 認可されているOAuthスコープ: openid
4 アカウントリンク設定
スキル側のアカウントリンクの設定は、以下のとおりです。
- Authorization Grant種別: Auth Code Grant (アプリの設定と整合させます)
- 認証画面のURL https://ユーザープールドメイン名/oauth2/authorize
- アクセストークンURL https://ユーザープールドメイン名/oauth2/token
- クライアントID: アプリの アプリクライントID (Cognito User Pool)
- クライアントシークレット: ID アプリのシークレット (Cognito User Pool)
- クライアントの認可方式: HTTP Basic認証(推奨)
- スコープ: openid
5 スキル有効化 / アカウント作成
スキルの有効化から、ユーザー登録までの流れは以下のとおりです。
- スキルを有効化します。
- ユーザID・パスワードに認証画面となるので、はじめての場合は、新規登録(Sign up)を選択します。
- Sign up時は、名前・パスワード。メールアドレスの他に、Profileの入力が求められますので、ここにデバイスIDを入力します。(注:図では、DEV12345となっていますが、テストは、1234567で行いました)
- 指定したメールアドレスに認証コードが送られて来ますので、これで認証します。
- 「正常にリンクされました」が表示されたら完了です。
- Cognito User Poolでも、ユーザーが追加されていることを確認できます。
6 スキルの実装
アカウントリンクが完了したスキルには、アクセストークンが送られてきますので、それを使用して、Cognito User PoolのAPIでProfile属性を取得します。
また、Profile属性をキーとしてDynamoDBからデータを取得します。
DynamoDBに保存されている情報は以下のようなものです。
コードは、以下のとおりです。
const LaunchRequestHandler = { canHandle(h) { return h.requestEnvelope.request.type === 'LaunchRequest'; }, async handle(h) { // User Poolから情報を取得する const domain = 'alexa-user-pool'; const url = 'https://' + domain + '.auth.ap-northeast-1.amazoncognito.com/oauth2/userInfo'; const accessToken = h.requestEnvelope.session.user.accessToken; const options = { uri: url, method: "GET", headers: { Authorization: 'Bearer ' + accessToken }, } const id = JSON.parse(await rp(options)).profile; // DynamoDBからデバイスIDに基づいたデータを検索する const data = await getDynamoDb('alexa-sample', id) const counter = data.Item.counter; const speechText = 'デバイスのカウンターは、' + counter + ' です。'; return h.responseBuilder .speak(speechText) .reprompt(speechText) .getResponse(); } }; async function getDynamoDb(tableName, id) { var docClient = new AWS.DynamoDB.DocumentClient(); var params = { TableName: tableName, Key:{ "device-id": id } }; return await docClient.get(params).promise(); }
スキルからは、以下のようメッセージが返されるはずです。
User: アレクサ、***をスタートしてして Alexa: デバイスのカウンターは、302です
7 最後に
今回は、OAuth2サーバを使用し、デバイスとスキルの紐づけを試してみました。
最初に、書いたとおりCognitoは、あくまで、ユーザー管理(+Auth2サーバ)として使用しているので、ユーザー管理ができるOAuth2サービス(任意の属性が保持できる)があれば、何でも同じような仕組みが作れると思います。
弊社では、Amazon Connectに関するキャンペーンを行なっています。
【6/27(木)東京】「1時間でクラウド型コンタクトセンターを構築できるようになる!無料Amazon Connectハンズオンセミナー」を開催します
また、音声を中心とした各種ソリューションの開発支援を行なっております。